#!/sbin/openrc-run

description="OpenBSD Secure Shell server"
description_checkconfig="Verify configuration file"
description_reload="Reload configuration"

extra_commands="checkconfig"
extra_started_commands="reload"

# NOTE: SSHD_* variables are deprecated and will be removed in future!
: "${sshd_disable_keygen:="${SSHD_DISABLE_KEYGEN:-"no"}"}"
: "${cfgfile:=${SSHD_CONFIG:-"${SSHD_CONFDIR:-"/etc/ssh"}/sshd_config"}}"

pidfile="${SSHD_PIDFILE:-"/run/$RC_SVCNAME.pid"}"
command="${SSHD_BINARY:-"/usr/sbin/sshd"}"
command_args="${command_args:-${SSHD_OPTS:-}}"

required_files="$cfgfile"

generate_host_key_type() {
	local bit_size key_type

	key_type=$1
	if [ ! -f /etc/ssh/ssh_host_"${key_type}"_key ]; then
		case $key_type in
			ecdsa)	bit_size="$ecdsa_bit_size";;
			rsa)	bit_size="$rsa_bit_size";;
		esac
		einfo "Generating $key_type SSH host key..."
		ssh-keygen \
			-q \
			-f /etc/ssh/ssh_host_"$key_type"_key \
			-N '' \
			-t "$key_type" \
			${bit_size:+ -b ${bit_size}} || return 1
	fi
}

generate_host_keys() {
	local type

	if [ -z "$key_types_to_generate" ] &&
	   [ -z "$ecdsa_bit_size" ] && [ -z "$rsa_bit_size" ]; then
		ssh-keygen -A
		return
	fi
	for type in ${key_types_to_generate:-dsa ecdsa ed25519 rsa}; do
		generate_host_key_type "$type" || return 1
	done
}

get_conf() {
	awk "/^$1\s/{ print \$2; exit }" "$cfgfile" /etc/ssh/sshd_config.d/*.conf 2>/dev/null
}

conf_enabled() {
	[ "$(get_conf "$1")" = "yes" ]
}

depend() {
	use logger dns
	after entropy

	if [ "${rc_need+set}" = "set" ] ; then
		: # Do nothing, the user has explicitly set rc_need
	else
		local x warn_addr
		# shellcheck disable=SC2013
		for x in $(get_conf ListenAddress) ; do
			case "$x" in
				0.0.0.0|0.0.0.0:*) ;;
				::|\[::\]*) ;;
				*) warn_addr="$warn_addr $x" ;;
			esac
		done
		if [ -n "$warn_addr" ] ; then
			need net
			ewarn "You are binding an interface in ListenAddress statement in your sshd_config!"
			ewarn "You must add rc_need=\"net.FOO\" to your /etc/conf.d/sshd"
			ewarn "where FOO is the interface(s) providing the following address(es):"
			ewarn "$warn_addr"
		fi
	fi
}

update_command() {
	if conf_enabled KerberosAuthentication || conf_enabled GSSAPIAuthentication && [ -r /usr/sbin/sshd.krb5 ]; then
		command="${SSHD_BINARY:-"/usr/sbin/sshd.krb5"}"
	elif conf_enabled UsePAM && [ -r /usr/sbin/sshd.pam ]; then
		command="${SSHD_BINARY:-"/usr/sbin/sshd.pam"}"
	fi
}

checkconfig() {
	update_command
	warn_deprecated_var SSHD_BINARY
	warn_deprecated_var SSHD_CONFDIR
	warn_deprecated_var SSHD_CONFIG cfgfile
	warn_deprecated_var SSHD_DISABLE_KEYGEN sshd_disable_keygen
	warn_deprecated_var SSHD_OPTS command_args
	warn_deprecated_var SSHD_PIDFILE

	if [ ! -d /var/empty ] ; then
		mkdir -p /var/empty || return 1
	fi

	if ! yesno "$sshd_disable_keygen"; then
		generate_host_keys || return 1
	fi

	[ "$pidfile" != "/run/sshd.pid" ] \
		&& command_args="$command_args -o PidFile=$pidfile"

	[ "$cfgfile" != "/etc/ssh/sshd_config" ] \
		&& command_args="$command_args -f $cfgfile"

	# shellcheck disable=SC2086
	"$command" -t $command_args || return 1
}

start_pre() {
	checkconfig
}

stop_pre() {
	update_command
	if [ "${RC_CMD}" = "restart" ] ; then
		checkconfig || return 1
	fi
}

stop_post() {
	if [ "$RC_RUNLEVEL" = "shutdown" ]; then
		_sshd_pids=$(pgrep "${command##*/}:")
		if [ -n "$_sshd_pids" ]; then
			ebegin "Shutting down ssh connections"
			# shellcheck disable=SC2086
			kill -TERM $_sshd_pids >/dev/null 2>&1
			eend 0
		fi
	fi
}

reload() {
	checkconfig || return 1

	ebegin "Reloading $RC_SVCNAME"
	start-stop-daemon --signal HUP \
		--exec "$command" --pidfile "$pidfile"
	eend $?
}

warn_deprecated_var() {
	local varname="$1"
	local replacement="${2:-}"

	eval "test -n \"\$$varname\"" || return 0

	ewarn "Variable \$$varname is deprecated and will be removed in the future!"
	# shellcheck disable=SC2015
	[ "$replacement" ] && ewarn "Use \$$replacement instead of \$$varname." ||:
}
